package cn.yunbamboos.db;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjUtil;
import cn.yunbamboos.db.metadata.TableMetadata;
import cn.yunbamboos.mybatis.annotation.TableField;
import cn.yunbamboos.mybatis.annotation.TableName;
import cn.yunbamboos.mybatis.annotation.TablePrimaryKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * 配置  JVM_OPTION
 * 检查是否更新数据库表 CHECK_DB 默认值： true
 * 数据库驱动 DB_DRIVER  默认值： com.mysql.cj.jdbc.Driver
 * 数据库IP DB_IP 默认值：127.0.0.1
 * 数据库端口 DB_PORT 默认值：3306
 * 数据库名称 DB_NAME 默认值：db
 * 数据库账号 DB_USER 默认值： root
 * 数据库密码 DB_PASSWORD 默认值： root
 */
public class DB {

    private static final Logger logger = LoggerFactory.getLogger(DB.class);
    /**
     * Model模型类
     * */
    private static final List<Class<?>> classes = new ArrayList<>();
    /**
     * 初始化SQL语句
     * */
    private static final String INIT_SQL_PATH = System.getProperty("user.dir")
            + File.separator + "data"
            + File.separator + "sql" + File.separator;


    public static void addModelClass(Class<?> modelClass){
        classes.add(modelClass);
    }

    public static String generateSql(){
        // 读取带TableName注解的类
        List<TableMetadata> tableMetadataList = read();
        StringBuilder builder = new StringBuilder();

        for (TableMetadata tableMetadata : tableMetadataList) {
            builder.append(tableMetadata.toCreateTableSql()).append("\n");
        }
        return builder.toString();
    }

    public static void check(String packageName) {
        boolean check = "true".equals(System.getProperty("CHECK_DB", "false"));
        logger.info("DB CHECK_DB {}", check);
        if (!check) {
            return;
        }
        // 读取带TableName注解的类
        List<TableMetadata> tableMetadataList = read(packageName);
        IDB db = DBFactory.getDB();
        // 检查数据库目录 为空解压初始化文件
        db.checkDBDir();
        // 检查数据库进程
        db.checkPid();
        // 连接数据库并检查连接是否成功
        db.connect();
        // 检查库是否存在
        if (!db.existDB()) {
            db.createDB();
        }
        for (TableMetadata tableMetadata : tableMetadataList) {
            // 检查数据库表
            if (!db.existTable(tableMetadata)) {
                logger.info("create table {}", tableMetadata.getName());
                // 创建数据库表
                db.createTable(tableMetadata);
            }
        }
        // 执行初始化SQL
        ReadInitDataSQL read = new ReadInitDataSQL(INIT_SQL_PATH);
        db.initDataSQL(read);
        db.closeDB();
    }

    public static List<TableMetadata> read() {
        return read(classes);
    }

    public static List<TableMetadata> read(String packageName) {
        Set<Class<?>> classes = ClassUtil.scanPackageByAnnotation(packageName, TableName.class);
        return read(classes);
    }

    public static List<TableMetadata> read(Collection<Class<?>> classes) {
        List<TableMetadata> tableMetadataList = new ArrayList<>();
        for (Class<?> clazz : classes) {
            TableName tableName = clazz.getAnnotation(TableName.class);
            if (ObjUtil.isNotNull(tableName)) {
                TableMetadata tableMetadata = new TableMetadata(tableName.value(), tableName.cn());
                // 读取数据库的列
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    TablePrimaryKey pk = field.getAnnotation(TablePrimaryKey.class);
                    if (ObjUtil.isNotNull(pk)) {
                        tableMetadata.addColumn(pk.value(), pk.type(), pk.length(), pk.cn(), pk.sort(), true);
                    }
                    TableField column = field.getAnnotation(TableField.class);
                    if (ObjUtil.isNotNull(column)) {
                        tableMetadata.addColumn(column.value(), column.type(), column.length(), column.cn(), column.sort());
                    }
                }
                tableMetadataList.add(tableMetadata);
                logger.info("read {} table: {} cn: {}", clazz.getName(), tableName.value(), tableName.cn());
            }
        }
        return tableMetadataList;
    }
}
